package com.xuecheng.order.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.commons.constants.OrdersConstants;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.dto.RecordDto;
import com.xuecheng.commons.model.vo.*;
import com.xuecheng.commons.utils.AuthInfoHolder;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.api.ContentClient;
import com.xuecheng.learning.api.LearningClient;
import com.xuecheng.order.domain.Orders;
import com.xuecheng.order.domain.OrdersExcel;
import com.xuecheng.order.domain.Payment;
import com.xuecheng.order.mappers.OrdersMapper;
import com.xuecheng.order.service.OrdersService;
import com.xuecheng.order.service.PaymentService;
import com.xuecheng.order.utils.PayUtils;
import com.xuecheng.search.api.SearchClient;
import com.xuecheng.web.exceptions.BusinessException;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 订单 服务实现类
 */
@Service
@Slf4j
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService {

    @Autowired
    private SearchClient searchClient;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private LearningClient learningClient;
    @Autowired
    private ContentClient contentClient;

    @Override
    public ResponseResult<List<UserOrdersVo>> selectUserOrder(String id) {
        LambdaQueryWrapper<Orders> qw = new LambdaQueryWrapper<>();
        qw.eq(Orders::getUserId,id);
        List<Orders> list = this.list(qw);
        ArrayList<UserOrdersVo> userOrdersVos = new ArrayList<>();
        list.forEach(e ->{
            ResponseResult<CoursePubVo> byId = contentClient.findById(e.getCoursePubId());
            userOrdersVos.add(new UserOrdersVo(e.getId(),e.getOrderNo(),e.getCoursePubId(),e.getCoursePubName(),e.getUserId(),e.getUserName(),e.getPrice(),e.getStatus(),byId.getData().getPic(),byId.getData().getPrice(),e.getCreateDate()));
        });
        return ResponseResult.okResult(userOrdersVos);
    }

    @Override
    public ResponseResult<List> selectOrder() {
        return ResponseResult.okResult(this.list());
    }

    @SneakyThrows
    @Override
    public ResponseResult excelDownload(HttpServletResponse httpServletResponse, String companyId) {
        LambdaQueryWrapper<Orders> qw = new LambdaQueryWrapper<>();
        qw.eq(Orders::getCompanyId,companyId);
        List<Orders> list = this.list(qw);
        ArrayList<OrdersExcel> ordersExcels = ListUtils.newArrayList();
        list.forEach(e ->{
            OrdersExcel ordersExcel = new OrdersExcel(e.getOrderNo(), e.getCreateDate(), e.getUserId(), e.getCoursePubName(), e.getPrice(), e.getPrice(), e.getStatus());
            ordersExcels.add(ordersExcel);
        });
        return ResponseResult.okResult(ordersExcels);
    }

    //创建订单
    public ResponseResult<String> create(Long coursePubId) {
        Long userId = AuthInfoHolder.getUserId();
        //1、查询当前用户是否已经有已支付的订单数据
        LambdaQueryWrapper<Orders> qw = new LambdaQueryWrapper<>();
        qw.eq(Orders::getUserId,userId);
        qw.eq(Orders::getCoursePubId,coursePubId);
        qw.eq(Orders::getStatus, OrdersConstants.ORDER_PAID_STATUS); //已支付
        Orders one = this.getOne(qw);
        if(one!=null) {
            throw new BusinessException(ErrorCode.ORDERERROR);
        }
        //2、查询当前用户是否已经有已下单，待支付的订单数据，如果存在，返回
        LambdaQueryWrapper<Orders> qw1 = new LambdaQueryWrapper<>();
        qw1.eq(Orders::getUserId,userId);
        qw1.eq(Orders::getCoursePubId,coursePubId);
        qw1.eq(Orders::getStatus, OrdersConstants.ORDER_INIT_STATUS); //已下单，未支付
        one = this.getOne(qw1);
        if(one!=null) {
            return ResponseResult.okResult(one.getOrderNo());
        }
        //3、调用feign接口，查询当前课程的发布数据
        ResponseResult<CoursePubIndexVo> result = searchClient.findById(coursePubId);
        CoursePubIndexVo vo = result.getData();
        //4、构造Order对象，设置属性
        Orders orders = new Orders();
        orders.setOrderNo(UUID.randomUUID().toString(true));
        orders.setCoursePubId(coursePubId);
        orders.setCoursePubName(vo.getName());
        orders.setCompanyId(vo.getCompanyId());
        orders.setUserId(userId);
        orders.setCreateDate(new Date());
        orders.setPrice(1l); //单位是分，1分钱
        orders.setStatus(OrdersConstants.ORDER_INIT_STATUS); //状态：初始状态
        //5、保存到数据库中
        boolean save = this.save(orders);
        if(!save) {
            throw new BusinessException(ErrorCode.ERROR);
        }
        //6、返回
        return ResponseResult.okResult(orders.getOrderNo());
    }

    @Autowired
    private PayUtils payUtils;

    //根据orderNo查询，订单的支付状态
    @GlobalTransactional //开启分布式事务处理
    public ResponseResult<OrdersVo> queryOrders(String orderNo) {
        //1、根据订单orderNo查询订单
        LambdaQueryWrapper<Orders> qw = new LambdaQueryWrapper<>();
        qw.eq(Orders::getOrderNo,orderNo);
        Orders orders = this.getOne(qw);
        //2、如果订单不存在，抛出异常
        if(orders == null) {
            throw  new BusinessException(ErrorCode.NOTFOUND);
        }
        //3、如果订单存在,且未支付状态
        if(orders.getStatus().equals(OrdersConstants.ORDER_INIT_STATUS)) {
            //4、查询微信的支付状态,如果微信支付成功
            Boolean payment = payUtils.checkPayment(orderNo);
            if(payment) {
                //4.1 更新订单表
                orders.setStatus(OrdersConstants.ORDER_PAID_STATUS);
                this.updateById(orders);
                //4.2 更新支付表
                LambdaQueryWrapper<Payment> pqw = new LambdaQueryWrapper<>();
                pqw.eq(Payment::getOrderNo,orderNo);
                Payment payment1 = paymentService.getOne(pqw);
                payment1.setStatus(OrdersConstants.PAID.toString());
                paymentService.updateById(payment1);
                //4.3 调用feign接口，保存或者更新选课记录
                RecordDto dto = new RecordDto();
                dto.setUserId(AuthInfoHolder.getUserId());
                dto.setCoursePubId(orders.getCoursePubId());
                learningClient.saveRecord(dto);
            }
        }
        //5、返回
        OrdersVo vo = BeanHelper.copyProperties(orders, OrdersVo.class);
        return ResponseResult.okResult(vo);
    }

    //清理超时订单
    @GlobalTransactional
    public void getPayment() {
        //1、查询15分钟之前创建的，未支付的订单
        LambdaQueryWrapper<Orders> qw = new LambdaQueryWrapper<>();
        String time = DateUtil.offsetMinute(new Date(), 15).toString();//获取15分钟之前的时间
        qw.lt(Orders::getCreateDate,time);
        qw.eq(Orders::getStatus,OrdersConstants.ORDER_INIT_STATUS);
        List<Orders> list = this.list(qw);
        log.info("超时订单共有:"+list); //mp查询list集合，如果没有数据，是一个空的数组，不是null
        //2、循环超时订单
        for (Orders orders : list) {
            log.info("处理超时订单：{}",orders.getOrderNo());
            //3、调用微信，获取每个订单在微信的支付状态
            Boolean payment = payUtils.checkPayment(orders.getOrderNo());
            //3.1 如果已支付，更新订状态，创建选课记录
            if(payment) {
                //更新订单表
                orders.setStatus(OrdersConstants.ORDER_PAID_STATUS);
                this.updateById(orders);
                //更新支付表
                LambdaQueryWrapper<Payment> pqw = new LambdaQueryWrapper<>();
                pqw.eq(Payment::getOrderNo,orders.getOrderNo());
                Payment payment1 = paymentService.getOne(pqw);
                payment1.setStatus(OrdersConstants.PAID.toString());
                paymentService.updateById(payment1);
                //调用feign接口，保存或者更新选课记录
                RecordDto dto = new RecordDto();
                dto.setUserId(orders.getUserId());
                dto.setCoursePubId(orders.getCoursePubId());
                learningClient.saveRecord(dto);
            }else {
                //3.2 如果未支付，关闭订单，通知微信关闭
                orders.setStatus(OrdersConstants.ORDER_CLOSED_STATUS);
                this.updateById(orders);
                payUtils.closeOrder(orders.getOrderNo());
            }

        }
    }

    public static void main(String[] args) {
        System.out.println(UUID.randomUUID().toString(true));
    }
}
